package com.wkbb.common.handler;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.AnnotationUtils;

import java.io.OutputStream;
import java.util.List;
import java.util.Map;

@Slf4j
public class JsonUtil {

    private static ObjectMapper mapper = new ObjectMapper();

    static {
        // 解决实体未包含字段反序列化时抛出异常
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        // 对于空的对象转json的时候不抛出错误
        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);

        // 允许属性名称没有引号
        mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);

        // 允许单引号
        mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
    }

    /**
     *
     * <b>Description:</b> 将一个object转换为json, 可以使一个java对象，也可以使集合<br>
     * <b>Title:</b> ObjectToJson<br>
     *
     * @param obj
     *            - 传入的数据
     * @return
     * @Note <b>Author:</b> luozhen <br>
     *       <b>Date:</b> 2018年5月24日 下午1:26:53 <br>
     *       <b>Version:</b> 1.0
     */
    public static String objectToJson(Object obj) {
        String json = null;
        try {
            json = mapper.writeValueAsString(obj);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return json;
    }

    /**
     * ObjectMapper支持从byte[]、File、InputStream、字符串等数据的JSON反序列化。
     */

    /**
     *
     * <b>Description:</b> 将json结果集转化为对象<br>
     * <b>Title:</b> jsonToClass<br>
     *
     * @param json
     *            - json数据
     * @param beanType
     *            - 转换的实体类型
     * @return
     * @Note <b>Author:</b> luozhen <br>
     *       <b>Date:</b> 2018年5月24日 下午3:26:18 <br>
     *       <b>Version:</b> 1.0
     */
    public static <T> T jsonToClass(String json, Class<T> beanType) {
        T t = null;
        try {
            t = mapper.readValue(json, beanType);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return t;
    }

    /**
     *
     * <b>Description:</b> 将json数据转换成Map<br>
     * <b>Title:</b> jsonToMap<br>
     *
     * @param json
     *            - 转换的数据
     * @return
     * @Note <b>Author:</b> luozhen <br>
     *       <b>Date:</b> 2018年5月24日 下午3:29:37 <br>
     *       <b>Version:</b> 1.0
     */
    public static Map<String, Object> jsonToMap(String json) {
        Map<String, Object> map = null;
        try {
            map = mapper.readValue(json, new TypeReference<Map<String, Object>>() {});
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    /**
     *
     * <b>Description:</b> 将json数据转换成list <br>
     * <b>Title:</b> jsonToList<br>
     *
     * @param json
     *            - 转换的数据
     * @return
     * @Note <b>Author:</b> luozhen <br>
     *       <b>Date:</b> 2018年5月24日 下午3:28:35 <br>
     *       <b>Version:</b> 1.0
     */
    public static <T> List<T> jsonToList(String json, Class<T> beanType) {
        List<T> list = null;
        try {
            JavaType javaType = mapper.getTypeFactory().constructParametricType(List.class, beanType);
            list = mapper.readValue(json, javaType);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }

    /**
     *
     * <b>Description:</b> 获取json对象数据的属性<br>
     * <b>Title:</b> findValue<br>
     *
     * @param resData
     *            - 请求的数据
     * @param resPro
     *            - 请求的属性
     * @return 返回String类型数据
     * @Note <b>Author:</b> luozhen <br>
     *       <b>Date:</b> 2018年5月31日 上午10:00:09 <br>
     *       <b>Version:</b> 1.0
     */
    public static String findValue(String resData, String resPro) {
        String result = null;
        try {
            JsonNode node = mapper.readTree(resData);
            JsonNode resProNode = node.get(resPro);
            result = JsonUtil.objectToJson(resProNode);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public static String stringify(Object object) {

        try {
            return mapper.writeValueAsString(object);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        return null;
    }

    public static String stringify(Object object, String... properties) {

        try {
            return mapper
                    .writer(new SimpleFilterProvider().addFilter(
                            AnnotationUtils.getValue(
                                    AnnotationUtils.findAnnotation(object.getClass(), JsonFilter.class)).toString(),
                            SimpleBeanPropertyFilter.filterOutAllExcept(properties)))
                    .writeValueAsString(object);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        return null;
    }

    public static void stringify(OutputStream out, Object object) {

        try {
            mapper.writeValue(out, object);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    public static void stringify(OutputStream out, Object object, String... properties) {

        try {
            mapper
                    .writer(new SimpleFilterProvider().addFilter(
                            AnnotationUtils.getValue(
                                    AnnotationUtils.findAnnotation(object.getClass(), JsonFilter.class)).toString(),
                            SimpleBeanPropertyFilter.filterOutAllExcept(properties)))
                    .writeValue(out, object);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    public static void main(String[] args) {
        JSONObject json = JSONObject.parseObject("{\"errcode\":40029,\"errmsg\":\"invalid code, rid: 62b271df-36524605-0020d3ba\"}");

        String sessionKey = json.getString("session_key");
        String openId = json.getString("openid");
        String unionId = json.getString("unionid");
        System.out.println(sessionKey);
        System.out.println(openId);
        System.out.println(unionId);
    }
}
